#include "appmanager.h"
#include "mainmenu.h"
#include "level.h"
#include "leveleditor.h"
#include "levelbrowser.h"
#include "levelmanager.h"
#include "playground.h"

AppManager::AppManager(QObject *parent) :
    QObject(parent), minWindowSize(QSize(800, 554)), selectType(DEFAULT),
    normalCursor(QCursor(QPixmap(":/cursor-normal"), 6, 6)),
    linerCursor(QCursor(QPixmap(":/cursor-liner"), 0, 0)),
    crossCursor(QCursor(QPixmap(":/cursor-cross"), 15, 15)),
    pickerCursor(QCursor(QPixmap(":/cursor-picker"), 15, 0)),
    grabberCursor(QCursor(QPixmap(":/cursor-grabber"), 15, 0)),
    handerCursor(QCursor(QPixmap(":/cursor-hander"), 15, 0))
{
    initScene();
    initResources();
    initEventSystem();
}

void AppManager::start()
{
    gShowMainMenu();
    mainWindow->show();
}

void AppManager::initScene()
{
    mainWindow = new QGraphicsView();
    mainWindow->setMinimumSize(minWindowSize);
    mainWindow->setMouseTracking(true);
    mainWindow->setWindowIcon(QIcon(QPixmap(":/logo")));
    changeCursor(NORMAL);

    // The width and height of scene is a little bit smaller than window.
    qreal sceneWidth = qreal(minWindowSize.width())-2;
    qreal sceneHeight = qreal(minWindowSize.height())-2;

    mainMenuScene = new QGraphicsScene(-sceneWidth/2, -sceneHeight/2,
                                       sceneWidth, sceneHeight);
    editorScene = new QGraphicsScene(-sceneWidth/2, -sceneHeight/2,
                                       sceneWidth, sceneHeight);
    selectorScene = new QGraphicsScene(-sceneWidth/2, -sceneHeight/2,
                                       sceneWidth, sceneHeight);
    playgroundScene = new QGraphicsScene(-sceneWidth/2, -sceneHeight/2,
                                       sceneWidth, sceneHeight);

}

void AppManager::initResources()
{
    mainMenu = new MainMenu(NULL, mainMenuScene);
    levelEditor = new LevelEditor(NULL, editorScene);
    levelBrowser = new LevelBrowser(NULL, selectorScene);
    levelManager = new LevelManager();
    playground = new Playground(NULL, playgroundScene);

    QFontDatabase::addApplicationFont(":/janis-font");
}

void AppManager::initEventSystem()
{
    connect(mainMenu, SIGNAL(exitClicked()), this, SLOT(gExitApp()));
    connect(mainMenu, SIGNAL(editorClicked()), this, SLOT(mEditorClicked()));
//    connect(mainMenu, SIGNAL(aboutClicked()), this, SLOT(mAboutClicked()));
    connect(mainMenu, SIGNAL(levelClicked()), this, SLOT(mLevelClicked()));

    connect(levelEditor, SIGNAL(returnClicked()), this, SLOT(gShowMainMenu()));
    connect(levelEditor, SIGNAL(pointClicked()), this, SLOT(ePointClicked()));
    connect(levelEditor, SIGNAL(lineClicked()), this, SLOT(eLineClicked()));
    connect(levelEditor, SIGNAL(pointHoverEnter()), this, SLOT(gChangeCursorHander()));
    connect(levelEditor, SIGNAL(pointHoverLeave()), this, SLOT(gChangeCursorCross()));
    connect(levelEditor, SIGNAL(lineHoverEnter()), this, SLOT(gChangeCursorHander()));
    connect(levelEditor, SIGNAL(lineHoverLeave()), this, SLOT(gChangeCursorPicker()));
    connect(levelEditor, SIGNAL(linerHoverEnter()), this, SLOT(gChangeCursorLiner()));
    connect(levelEditor, SIGNAL(linerHoverLeave()), this, SLOT(gChangeCursorPicker()));
    connect(levelEditor, SIGNAL(pointDragStart()), this, SLOT(gChangeCursorGrabber()));
    connect(levelEditor, SIGNAL(pointDragStop()), this, SLOT(gChangeCursorHander()));
    connect(levelEditor, SIGNAL(lineDragStart()), this, SLOT(gChangeCursorGrabber()));
    connect(levelEditor, SIGNAL(lineDragStop()), this, SLOT(gChangeCursorPicker()));
    connect(levelEditor, SIGNAL(lineringStop()), this, SLOT(gChangeCursorPicker()));
    connect(levelEditor, SIGNAL(canvasHoverEnter(CanvasState)),
            this, SLOT(eChangeCursorWhenEntering(CanvasState)));
    connect(levelEditor, SIGNAL(canvasHoverLeave()), this, SLOT(gChangeCursorNormal()));
    connect(levelEditor, SIGNAL(loadClicked()), this, SLOT(eLoadLevel()));
    connect(levelEditor, SIGNAL(saveClicked(const QString&)), this, SLOT(eSaveLevel(const QString&)));

    connect(levelBrowser, SIGNAL(returnClicked()), this, SLOT(gShowMainMenu()));

    connect(levelBrowser, SIGNAL(levelSelected(int)), this, SLOT(gSelectLevel(int)));

    connect(playground, SIGNAL(returnClicked()), this, SLOT(gShowMainMenu()));
    connect(playground, SIGNAL(pointHoverEnter()), this, SLOT(gChangeCursorHander()));
    connect(playground, SIGNAL(pointHoverLeave()), this, SLOT(gChangeCursorNormal()));
    connect(playground, SIGNAL(lineHoverEnter()), this, SLOT(gChangeCursorHander()));
    connect(playground, SIGNAL(lineHoverLeave()), this, SLOT(gChangeCursorNormal()));
    connect(playground, SIGNAL(pointDragStart()), this, SLOT(gChangeCursorGrabber()));
    connect(playground, SIGNAL(pointDragStop()), this, SLOT(gChangeCursorHander()));
    connect(playground, SIGNAL(lineDragStart()), this, SLOT(gChangeCursorGrabber()));
    connect(playground, SIGNAL(lineDragStop()), this, SLOT(gChangeCursorHander()));
    connect(playground, SIGNAL(toNextLevel()), this, SLOT(pNextLevel()));
}

void AppManager::gExitApp()
{
    exit(0);
}

void AppManager::mEditorClicked()
{
    levelEditor->setEditingLevel(NULL);
    changeScene(EDITOR);
}

void AppManager::mLevelClicked()
{
    selectType = PLAY;
    levelBrowser->setBrowseType(LevelBrowser::PLAY);
    levelBrowser->setDisplayLevels(levelManager->getLevels());
    changeScene(SELECTOR);
}

//void AppManager::mAboutClicked()
//{
//}

void AppManager::eLineClicked()
{
    changeCursor(PICKER);
}

void AppManager::ePointClicked()
{
    changeCursor(CROSS);
}

void AppManager::eChangeCursorWhenEntering(CanvasState state)
{
    switch (state)
    {
    case commons::LINE: changeCursor(PICKER);break;
    case commons::POINT: changeCursor(CROSS);break;
    default: changeCursor(NORMAL);break;
    }
}

void AppManager::eLoadLevel()
{
    selectType = LOAD;
    levelBrowser->setBrowseType(LevelBrowser::LOAD);
    levelBrowser->setDisplayLevels(levelManager->getLevels());
    changeScene(SELECTOR);
}

void AppManager::eSaveLevel(const QString&)
{
    Level *level = levelEditor->getEditingLevel();
//    qDebug() << level->getId();
    levelManager->saveLevel(level);
}

void AppManager::gShowMainMenu()
{
    changeCursor(NORMAL);
    changeScene(MENU);
}

void AppManager::gChangeCursorCross()
{
    changeCursor(CROSS);
}

void AppManager::gChangeCursorGrabber()
{
    changeCursor(GRABBER);
}

void AppManager::gChangeCursorHander()
{
    changeCursor(HANDER);
}

void AppManager::gChangeCursorLiner()
{
    changeCursor(LINER);
}

void AppManager::gChangeCursorNormal()
{
    changeCursor(NORMAL);
}

void AppManager::gChangeCursorPicker()
{
    changeCursor(PICKER);
}

void AppManager::gSelectLevel(int id)
{
    switch (selectType)
    {
    case PLAY:
        playground->setPlayLevel(levelManager->getLevel(id));
        changeScene(PLAYGROUND);
        break;
    case LOAD:
        levelEditor->setEditingLevel(levelManager->getLevel(id));
        changeScene(EDITOR);
        break;
    default:break;
    }
}

void AppManager::pNextLevel()
{
    Level *level = levelManager->getLevel(playground->getCurrentLevel()->getId()+1);
    if (NULL == level)
        playground->setPlayLevel(levelManager->getLevel(1));
    else
        playground->setPlayLevel(level);
}

void AppManager::changeCursor(CursorType type)
{
    switch (type) {
    case NORMAL: mainWindow->setCursor(normalCursor);break;
    case LINER: mainWindow->setCursor(linerCursor);break;
    case CROSS: mainWindow->setCursor(crossCursor);break;
    case GRABBER: mainWindow->setCursor(grabberCursor);break;
    case HANDER: mainWindow->setCursor(handerCursor);break;
    case PICKER: mainWindow->setCursor(pickerCursor);break;
    default: mainWindow->setCursor(normalCursor);break;
    }
}

void AppManager::changeScene(SceneType type)
{
    switch (type) {
    case MENU: mainWindow->setScene(mainMenuScene);break;
    case EDITOR: mainWindow->setScene(editorScene);break;
    case SELECTOR: mainWindow->setScene(selectorScene);break;
    case PLAYGROUND: mainWindow->setScene(playgroundScene);break;
    }
    mainWindow->update();
}

AppManager::~AppManager()
{
    delete mainWindow;
}
